
// Copyright (C) 2007 Richard Uhler
// This file is part of Esiply.
//
// Esiply is free software; you can redistribute it and/or modify
// it under the terms of the GNU General Public License, Version 2,
// as published by the Free Software Foundation.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program.  If not, see <http://www.gnu.org/licenses/>.

#include <assert.h>
#include <stdio.h>
#include <vector>
#include <stdio.h>
#include <string.h>
#include "esni.h"
#include <stdlib.h>
#include <iostream>
#include <pthread.h>
extern int yydebug;
extern int yy_flex_debug;
esni_interface_t* esni;

esni_value_t em_print(esni_context_t context)
{
    // Convert the first argument to a string, and print it followed by
    // a newline.
    esni_value_t str;
    esni->evaluate(context, "$1 = str;", &str, NULL);
    printf("%s\n",esni->get_string(context, str));
    esni_value_t und;
    esni->evaluate(context, "$1 = undefined;", &und, NULL);
    return und;
}

esni_value_t em_debug(esni_context_t context)
{
    // debug does nothing for mozilla
    esni_value_t und;
    esni->evaluate(context, "$1 = undefined;", &und, NULL);
    return und;
}

esni_value_t em_quit(esni_context_t context)
{
    exit(EXIT_SUCCESS);
}


//pass param to new thread
struct Param{
	esni_value_t func;
	esni_context_t context;
};
void *thr_fn(void *arg)
{
    struct Param* p = (struct Param*)arg;
	esni->evaluate(p->context, "$1();", &(p->func), NULL);
	//free(p);
}
esni_value_t em_thread(esni_context_t context)
{
     // Convert the first argument to a string, and print it followed by
    // a newline.
    esni_value_t func;
    esni->evaluate(context, "$1 = func;", &func, NULL);
    //start new thread function
	
	int err;
    pthread_t ntid;
	struct Param* p = (Param*) malloc(sizeof(Param));
	p->func = func;
	p->context = context;
    err = pthread_create(&ntid, NULL, thr_fn, p);
	
	esni_value_t res;
    if (err != 0){
        //printf("can't create thread: %s\n", strerror(err));
		esni->evaluate(context, "$1 = false;", &res, NULL);
	}else{
		esni->evaluate(context, "$1 = true;", &res, NULL);
	}
    return res;
}
int main(int argc, char* argv[])
{
    yydebug = 0;
    yy_flex_debug = 0;
    esni = esni_get_interface();

    // mozilla is run like:
    // ./esiply-mozilla -f script1 -f script2
    // returns
    // 0: default
    // 1: initialization failure
    // 2: bad command line
    // 3: uncaught exception
    // 4: bad file

    std::vector<char*> scripts;
    for (int i = 1; i < argc; i++)
    {
        if (strcmp(argv[i], "-f") == 0)
        {
            scripts.push_back(argv[++i]);
        }
    }

    // Instantiate the interpreter
    esni_context_t context = esni->create(NULL);

    // Create the print function
    esni_value_t printfunc = esni->make_function(context, em_print, "str");
    esni->evaluate(context, "print = $1;", &printfunc, NULL);

    // Add debug function so libraries work
    esni_value_t debugfunc = esni->make_function(context, em_debug, "str");
    esni->evaluate(context, "debug = $1;", &debugfunc, NULL);

    // Quit function
    esni_value_t quitfunc = esni->make_function(context, em_quit, "");
    esni->evaluate(context, "quit = $1;", &quitfunc, NULL);

	// Thread function
    esni_value_t threadfunc = esni->make_function(context, em_thread, "func");
    esni->evaluate(context, "thread = $1;", &threadfunc, NULL);
	
    // version = ""
    esni->evaluate(context, "version = '';", NULL, NULL);

    // Run the files
    for (int i = 0; i < scripts.size(); i++)
    {
        // TODO: check the result for an exception.
        esni->run_file(context, scripts[i]);
    }
    return 0;
}

